package utils

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"gitee.com/sansaniot/ssiot-core/config"
	authJwt "gitee.com/sansaniot/ssiot-core/httpmvc/jwtauth"
	"github.com/dgrijalva/jwt-go"
)

const (
	HttpContentJson = "json"
	HttpContentForm = "form"
)

func HttpPost(api string, param map[string]interface{}, contentType string, header ...map[string]string) (map[string]interface{}, error) {
	var reqParam string
	var reqContentType string
	if contentType == HttpContentForm {
		reqContentType = "application/x-www-form-urlencoded"
		uv := url.Values{}
		for k, v := range param {
			var dataValue string
			switch v.(type) {
			case string:
				dataValue = v.(string)
			case float64:
				ft := v.(float64)
				dataValue = strconv.FormatFloat(ft, 'f', -1, 64)
			case float32:
				ft := v.(float32)
				dataValue = strconv.FormatFloat(float64(ft), 'f', -1, 64)
			case int:
				it := v.(int)
				dataValue = strconv.Itoa(it)
			case uint:
				it := v.(uint)
				dataValue = strconv.Itoa(int(it))
			case int8:
				it := v.(int8)
				dataValue = strconv.Itoa(int(it))
			case uint8:
				it := v.(uint8)
				dataValue = strconv.Itoa(int(it))
			case int16:
				it := v.(int16)
				dataValue = strconv.Itoa(int(it))
			case uint16:
				it := v.(uint16)
				dataValue = strconv.Itoa(int(it))
			case int32:
				it := v.(int32)
				dataValue = strconv.Itoa(int(it))
			case uint32:
				it := v.(uint32)
				dataValue = strconv.Itoa(int(it))
			case int64:
				it := v.(int64)
				dataValue = strconv.FormatInt(it, 10)
			case uint64:
				it := v.(uint64)
				dataValue = strconv.FormatUint(it, 10)
			case []byte:
				dataValue = string(v.([]byte))
			default:
				newValue, _ := json.Marshal(v)
				dataValue = string(newValue)
			}

			uv.Set(k, dataValue)
		}
		reqParam = uv.Encode()
	} else {
		reqContentType = "application/json"
		data, _ := json.Marshal(param)
		reqParam = string(data)
	}

	req, err := http.NewRequest("POST", api, strings.NewReader(reqParam))
	if err != nil {
		return nil, err
	}

	// 表单方式(必须)
	req.Header.Add("Content-Type", reqContentType)
	if len(header) > 0 {
		for k, v := range header[0] {
			req.Header.Add(k, v)
		}
	}
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	res := make(map[string]interface{})
	err = json.Unmarshal(body, &res)
	if err != nil {
		return nil, errors.New(string(body))
	}
	return res, nil
}

func HttpGet(url string, res *map[string]interface{}) {
	//获取微信用户openid
	resp, err := http.Get(url)
	defer func(Body io.ReadCloser) {
		_ = Body.Close()
	}(resp.Body)
	if err != nil {
		return
	}
	body, _ := ioutil.ReadAll(resp.Body)
	ConvtByteToMap(body, res)

}

func ParseToken(tokenStr string) map[string]interface{} {
	authJwt, _ := authJwt.New(&authJwt.GinJWTMiddleware{
		Realm:         "test zone",
		Key:           []byte("API" + config.JwtConfig.Secret),
		TokenLookup:   "header: Authorization, header: accessToken, cookie: token, cookie: jwt",
		TokenHeadName: "Bearer",
		TimeFunc:      time.Now,
	})
	token, _ := authJwt.ParseTokenString(tokenStr)
	if token == nil {
		return make(map[string]interface{})
	} else {
		claims := token.Claims.(jwt.MapClaims)
		return claims
	}
}

func HttpGetJson(url string, param map[string]string, header map[string]string, result interface{}) error {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return err
	}
	q := req.URL.Query()
	if param != nil {
		for k, v := range param {
			q.Add(k, v)
		}
	}
	if header != nil {
		for k, v := range header {
			req.Header.Add(k, v)
		}
	}
	req.URL.RawQuery = q.Encode()
	//logger.Infof("HTTP Get请求：%s, %s", url, req.URL.RawQuery)
	response, err := client.Do(req)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	err = json.Unmarshal(body, &result)
	if err != nil {
		return err
	}
	return nil
}

func HttpPostJson(url string, param map[string]interface{}, header map[string]string, result interface{}) error {
	buf := bytes.NewBuffer(nil)
	encoder := json.NewEncoder(buf)
	if err := encoder.Encode(param); err != nil {
		return err
	}
	request, err := http.NewRequest(http.MethodPost, url, buf)
	if err != nil {
		return err
	}
	request.Header.Add("Content-Type", "application/json")
	if header != nil {
		for k, v := range header {
			request.Header.Add(k, v)
		}
	}
	//logger.Infof("HTTP Post请求：%s, %s", url, buf.String())
	response, err := client.Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return err
	}
	err = json.Unmarshal(body, &result)
	if err != nil {
		return err
	}
	return nil
}
